package org.luxor.eshop.order.service;

import io.seata.spring.annotation.GlobalTransactional;
import org.luxor.commons.core.exception.BaseException;
import org.luxor.commons.core.exception.TransactionException;
import org.luxor.commons.core.utils.BeanUtils;
import org.luxor.commons.core.utils.CollectionUtils;
import org.luxor.commons.core.utils.IdWorker;
import org.luxor.eshop.order.entity.OrderCommodityEntity;
import org.luxor.eshop.order.entity.OrderEntity;
import org.luxor.eshop.order.entity.dto.CommodityDto;
import org.luxor.eshop.order.entity.dto.CreateOrderDto;
import org.luxor.eshop.order.entity.dto.DeductInventoryDto;
import org.luxor.eshop.order.entity.dto.OrderDto;
import org.luxor.eshop.order.mapper.OrderCommodityMapper;
import org.luxor.eshop.order.mapper.OrderMapper;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Date;
import java.util.List;
import java.util.stream.Collectors;

/**
 * 订单服务
 *
 * @author Mr.Yan  @date: 2020/11/24
 */
@Service
public class OrderService {

    @Resource
    private StorageFeign storageFeign;
    @Resource
    private OrderMapper orderMapper;
    @Resource
    private OrderCommodityMapper orderCommodityMapper;

    /**
     * 创建订单
     */
    @GlobalTransactional(rollbackFor = TransactionException.class)
    @Transactional(rollbackFor = TransactionException.class)
    public OrderDto create(CreateOrderDto createOrder) {

        List<CommodityDto> commodityLis = createOrder.getCommodityList();
        if (CollectionUtils.isEmpty(commodityLis)) {
            commodityLis = new ArrayList<>();
        }

        // 1.1 保存订单
        OrderEntity orderEntity = new OrderEntity();
        orderEntity.setOrderId(IdWorker.getId());
        orderEntity.setAccount(createOrder.getAccount());
        orderEntity.setStatus((byte) 0);
        orderEntity.setMoney(calculate(commodityLis));
        orderEntity.setCreateTime(new Date(System.currentTimeMillis()));
        orderEntity.setDueTime(new Date(System.currentTimeMillis() + 2 * 60 * 60 * 1000));
        orderMapper.insert(orderEntity);

        // 1.2 保存商品项列表
        for (CommodityDto commodity : commodityLis) {
            OrderCommodityEntity commodityEntity = BeanUtils.transform(OrderCommodityEntity.class, commodity);
            commodityEntity.setOrderId(orderEntity.getOrderId());
            orderCommodityMapper.insert(commodityEntity);
        }

        // 2 扣减库存
        Collection<DeductInventoryDto> deductInventory = commodityLis.stream().map(commodity ->
                new DeductInventoryDto(commodity.getCommodityCode(), commodity.getQuantity())
        ).collect(Collectors.toList());
        storageFeign.deductInventory(deductInventory).assertSuccess();

        // 3 构建响应内容
        OrderDto order = new OrderDto();
        order.setOrderId(orderEntity.getOrderId());
        order.setAccount(orderEntity.getAccount());
        order.setCommodityList(commodityLis);
        order.setMoney(orderEntity.getMoney());
        return order;
    }

    /**
     * 获取订单信息
     */
    public OrderDto get(Long orderId) {

        OrderEntity orderEntity = orderMapper.selectById(orderId);
        if (orderEntity == null) {
            throw new BaseException("订单不存在");
        }

        List<OrderCommodityEntity> orderCommodityRef = orderCommodityMapper.selectListByOrderId(orderId);
        List<CommodityDto> commodityLis = orderCommodityRef.stream().map(el ->
                BeanUtils.transform(CommodityDto.class, el))
                .collect(Collectors.toList());

        OrderDto order = new OrderDto();
        order.setOrderId(orderId);
        order.setAccount(orderEntity.getAccount());
        order.setMoney(orderEntity.getMoney());
        order.setCommodityList(commodityLis);
        return order;
    }


    public void paySuccess(Long orderId) {
        orderMapper.updatePayStatusByOrderId((byte) 1, orderId);
    }

    public void payFailed(Long orderId) {
        orderMapper.updatePayStatusByOrderId((byte) 2, orderId);
    }

    /**
     * 计算总价
     */
    private BigDecimal calculate(List<CommodityDto> commodityLis) {
        BigDecimal totalMoney = new BigDecimal("0.00");
        for (CommodityDto commodity : commodityLis) {
            totalMoney.add(commodity.getCommodityPrice());
        }
        return totalMoney;
    }
}
